맨위로가기

스트림 프로세싱

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

스트림 프로세싱은 데이터를 순차적으로 처리하는 방식이며, 초기에는 CPU의 한계를 극복하기 위해 SIMD와 같은 병렬 처리 기술의 대안으로 등장했다. 계산 집약적이고 데이터 병렬성이 높으며 데이터 지역성을 갖는 애플리케이션에 적합하며, 그래픽 처리, 이미지 처리, 비디오 인코딩, 무선 신호 처리 등 다양한 분야에 활용된다. 스트림 프로세싱은 범용 프로세서보다 효율적인 메모리 접근과 높은 병렬 처리를 통해 성능 향상을 이룰 수 있으며, 스탠퍼드 대학교, 삼성전자, LG전자 등에서 관련 연구가 진행되었다. 프로그래밍 모델로는 C++, C, Java 등을 기반으로 한 언어와 라이브러리가 사용되며, GPU, 셀 프로세서 등 다양한 하드웨어 아키텍처에서 구현된다.

더 읽어볼만한 페이지

  • GPGPU - 인텔 Xe
    인텔 Xe는 저전력부터 고성능 컴퓨팅까지 다양한 시장을 목표로 하는 인텔의 GPU 아키텍처 제품군으로, Xe-LP, Xe-HPG, Xe-HP, Xe-HPC 등의 하위 아키텍처를 가지며 외장 그래픽 카드인 인텔 아크 시리즈와 내장 그래픽, 데이터 센터용 GPU 등에 활용된다.
  • GPGPU - 테라스케일 (마이크로아키텍처)
    테라스케일은 AMD가 개발한 GPU 마이크로아키텍처로, 셰이더 처리량 증가를 위해 통합 셰이더 모델을 사용하며, VLIW 아키텍처를 기반으로 라데온 HD 2000, 3000, 4000, 5000, 6900 시리즈에 적용되었다가 그래픽스 코어 넥스트 아키텍처로 대체되었다.
  • 계산 모형 - 양자 컴퓨터
    양자 컴퓨터는 양자역학적 현상을 이용하여 정보를 처리하는 컴퓨터로, 큐비트를 통해 0과 1을 동시에 표현하여 특정 연산에서 기존 컴퓨터보다 빠른 속도를 보이며 암호 해독, 신약 개발 등 다양한 분야에 혁신을 가져올 것으로 기대된다.
  • 계산 모형 - 양자 회로
    양자 회로는 양자 컴퓨팅에서 양자 논리 게이트들을 연결한 회로로, 큐비트의 양자역학적 특성을 활용하여 계산을 수행하며 양자 계산의 핵심 요소로서 연구가 활발히 진행되고 있다.
  • 컴퓨터 구조 - PA-RISC
    PA-RISC는 휴렛 팩커드에서 개발한 RISC 기반 명령어 집합 아키텍처로, HP 서버 및 워크스테이션에 사용되었으며 대용량 L1 캐시와 SIMD 명령어 확장 등의 특징을 가졌으나 아이테니엄 아키텍처로의 전환으로 단종되었다.
  • 컴퓨터 구조 - 메모리 관리
    메모리 관리는 운영체제의 핵심 기능으로, 여러 프로세스의 원활한 실행을 위해 메모리 공간을 할당하고 관리하며, 릴로케이션, 보호, 공유, 가상 메모리 관리, 자동/수동 메모리 관리 등의 기능을 수행한다.
스트림 프로세싱
스트림 프로세싱
유형컴퓨팅
하위 분류프로그래밍 패러다임
관련 항목병렬 컴퓨팅
반응형 프로그래밍
데이터 흐름 프로그래밍
이벤트 스트림 처리
복합 이벤트 처리
온라인 분석 처리
스트림 SQL
기타
고려 사항스트림 프로세싱 시스템
분산 스트림 프로세싱
스트림 프로세싱 엔진
스트림 프로세싱 아키텍처
스트림 프로세싱 프로그래밍 모델
스트림 프로세싱 기술
스트림 프로세싱 애플리케이션
스트림 프로세싱 플랫폼
스트림 프로세싱 프레임워크

2. 역사적 배경

컴퓨터 기술의 초기 단계에서는 CPU가 한 번에 하나의 명령어와 데이터를 처리하는 SISD (Single Instruction, Single Data) 방식, 즉 순차적 실행 패러다임을 따랐다. 그러나 처리해야 할 데이터의 양이 급격히 증가하면서 이러한 순차적 방식만으로는 늘어나는 컴퓨팅 요구를 감당하기 어려워졌다.

이러한 문제를 해결하기 위해 대량의 데이터를 효율적으로 처리할 수 있는 병렬 처리 방식이 모색되었다. 그 결과, 하나의 명령어로 여러 데이터를 동시에 처리하는 SIMD (Single Instruction, Multiple Data)와 여러 명령어로 여러 데이터를 동시에 처리하는 MIMD (Multiple Instruction, Multiple Data)와 같은 병렬 프로그래밍 패러다임이 등장하게 되었다. 이러한 병렬 처리 기술의 발전은 스트림 프로세싱 개념의 중요한 역사적 배경이 되었다.

2. 1. 초기 역사

초기 컴퓨터CPU가 한 번에 하나의 연산만 수행하는 SISD (Single Instruction, Single Data) 방식을 기반으로 동작했다. 이는 순차적 실행 패러다임으로, 개념적으로 한 번에 하나의 작업만 처리하는 것을 의미한다.

그러나 컴퓨팅 기술의 발전과 함께 처리해야 할 데이터의 양이 급격히 증가하면서, 기존의 순차적 프로그래밍 모델로는 늘어나는 처리 요구량을 감당하기 어려워졌다. 대량의 계산을 효율적으로 수행하기 위한 대안으로 병렬 실행 방식이 모색되었고, 그 결과 여러 데이터에 대해 하나의 명령어를 동시에 적용하는 SIMD (Single Instruction, Multiple Data) 프로그래밍 패러다임이 등장했다. SIMD는 주로 SWAR (SIMD Within A Register, 레지스터 내 SIMD) 환경에서 활용되었으며, 더 복잡한 구조를 통해 여러 명령어를 여러 데이터에 동시에 적용하는 MIMD (Multiple Instruction, Multiple Data) 병렬 처리 방식도 가능해졌다.

SIMD와 MIMD는 효율적인 병렬 처리 방식이었지만, 실제 구현에서는 메모리 정렬 문제, 동기화의 어려움, 제한된 병렬 수준 등 여러 제약에 부딪혔다. 이로 인해 독립적인 SIMD 전용 프로세서는 점차 사라지고, 대부분의 SIMD 기능은 범용 CPU의 명령어 집합 일부로 통합되는 형태로 발전했다.

SIMD의 효율성을 이해하기 위해 100개의 4차원 벡터(총 400개의 숫자)를 요소별로 더하는 간단한 예시를 살펴보자.

순차적 방식으로 이 계산을 수행하면 다음과 같은 코드가 된다.



for (int i = 0; i < 400; i++)

result[i] = source0[i] + source1[i];



이 코드에서는 덧셈 연산이 400번 반복되며, 루프를 제어하기 위한 조건 분기나 인덱스 증가 등의 부가적인 명령어도 많이 실행된다.

반면, 4개의 요소를 한 번에 계산할 수 있는 SIMD 명령(예: `vector_sum`)을 사용하면 코드는 다음과 같이 바뀐다. (벡터 차원이나 데이터 형식 등 세부 사항은 생략)



for (int el = 0; el < 100; el++) // 각 벡터에 대해

vector_sum(result[el], source0[el], source1[el]); // 4개 덧셈 동시 처리 가정



이 방식에서는 4개의 덧셈 연산을 한 번의 명령으로 처리하므로, 덧셈 관련 명령어의 수가 1/4로 줄어든다. 또한 루프 반복 횟수도 100번으로 감소하여 전체 실행 명령어 수가 크게 줄어든다.

하지만 SIMD 방식의 병렬성에는 한계가 있다. 한 번에 처리할 수 있는 데이터의 양은 SIMD 레지스터의 크기에 의해 제한되기 때문이다. 위 예시에서는 4개의 연산을 병렬로 수행하므로, 이론적인 속도 향상은 최대 4배에 그친다. 이러한 제약은 AltiVec이나 SSE와 같은 실제 SIMD 기술에서도 동일하게 나타난다.

2. 2. 스탠퍼드 대학교의 연구

스탠퍼드 대학교는 스트림 프로세싱 분야에서 중요한 연구를 수행해왔다. 1999년에는 스탠퍼드 실시간 프로그래밍 가능 셰이딩 프로젝트(Stanford Real-Time Programmable Shading Project)가 시작되었으며,[7] 이는 Stanford Shading language 개발로 이어졌다.

이후 2002년에는 프로토타입 스트림 프로세서인 Imagine이 개발되었고,[8] 스트림 프로세싱 패러다임의 가능성을 보여주었다. 이러한 성과를 바탕으로 더 큰 규모의 프로젝트인 Merrimac이 2004년까지 진행되었다.[9] Merrimac은 스트림 기반 슈퍼컴퓨터 개발을 목표로 했다.

2005년 9월 당시에는 스트림 프로세싱에 관한 자료가 매우 부족했으며, 소수의 기관만이 이 기술의 잠재력을 인식하고 있었다. 스탠퍼드 대학교는 이 분야 연구를 선도하는 대표적인 기관이었다.

한편, AT&T 역시 GPU의 빠른 성능 및 기능 향상과 맞물려 스트림 처리 기능을 강화한 프로세서에 대한 연구를 진행했다. 이러한 초기 연구 이후 수십 개의 스트림 처리 언어와 특수 하드웨어가 개발되었다.

3. 주요 특징

스트림 프로세싱은 본질적으로 데이터 중심 모델을 기반으로 하며, 전통적인 디지털 신호 처리 (DSP)나 GPU 유형의 애플리케이션(예: 이미지, 비디오 및 디지털 신호 처리)에는 매우 적합하다. 반면, 데이터 접근이 무작위적인 일반적인 처리(예: 데이터베이스)에는 덜 적합하다. 모델의 유연성을 일부 희생하는 대신 더 쉽고, 빠르며, 효율적인 실행을 가능하게 하는 접근 방식이다. 상황에 따라, 프로세서 설계는 최대 효율성을 위해 조정되거나 유연성을 위해 절충될 수 있다.

스트림 프로세싱은 특히 다음 세 가지 애플리케이션 특성을 나타내는 경우에 효과적이다.


  • '''계산 집약도''': I/O 또는 전역 메모리 참조당 수행되는 산술 연산의 수.[1]
  • '''데이터 병렬성''': 동일한 함수(커널)가 입력 스트림의 모든 레코드에 적용되고, 이전 레코드의 결과를 기다리지 않고 여러 레코드를 동시에 처리할 수 있는 특성.[1]
  • '''데이터 지역성''': 데이터가 한 번 생성되고, 애플리케이션에서 한두 번 읽혀지고, 다시는 읽히지 않는 특정 유형의 시간적 지역성.[1]


이러한 특징 덕분에 스트림 프로세싱은 스트림이라 불리는 데이터 흐름에 커널이라는 연산을 효율적으로 적용하여 높은 처리 성능을 달성한다. 스트림과 커널의 개념은 데이터 의존성을 명시적으로 하여 컴파일러가 메모리 관리 등을 최적화하는 데 도움을 준다. 온칩 메모리의 효율적인 사용은 ALU에 더 많은 칩 면적을 할당할 수 있게 한다.

스트림 프로세싱은 SIMD/MIMD 프로세싱의 한 분야이지만, 단순히 동일한 개념으로 혼동해서는 안 된다. SIMD 구현이 "스트리밍" 방식으로 작동할 수 있지만, 스트림 프로세싱 모델은 매우 다른 사용 패턴을 상정하고 있어 훨씬 더 뛰어난 성능을 낼 수 있다. 일반적인 CPU에 적용할 경우 제한적인 성능 향상만 보일 수 있지만,[5] 스트림 프로세서 아키텍처는 효율적인 메모리 접근과 높은 수준의 병렬 처리를 통해 10배 이상의 성능 향상도 가능하다.[6]

그러나 스트림 프로세싱 모델에서 허용되는 유연성의 정도는 다양하며, 스트림 프로세서는 일반적으로 커널이나 스트림 크기, 지원하는 연산(예: 고정밀 수학, 복잡한 간접 참조) 등에서 몇 가지 제한을 가질 수 있다.

3. 1. 계산 집약도

스트림 프로세싱은 특정 특성을 가진 애플리케이션에 특히 유리하며, 그중 하나가 계산 집약도이다.[1] 계산 집약도는 I/O 작업이나 전역 메모리 참조 한 번당 수행되는 산술 연산의 수를 의미한다.[1]

오늘날 많은 디지털 신호 처리 (DSP) 애플리케이션에서는 이 비율이 50:1을 훨씬 넘어서는 경우가 많으며, 알고리즘의 복잡성이 증가함에 따라 계산 집약도 역시 높아지는 경향이 있다.[1] 즉, 데이터 전송량에 비해 계산량이 많은 애플리케이션일수록 스트림 프로세싱의 효율성이 높아진다. 이는 스트림 프로세싱이 GPU와 같이 대량의 연산을 병렬로 처리하는 데 특화된 아키텍처에서 주로 활용되는 이유 중 하나이다.[1]

3. 2. 데이터 병렬성

'''데이터 병렬성'''은 동일한 함수(커널)가 입력 스트림의 모든 레코드에 적용될 때 존재하며, 이전 레코드의 결과를 기다리지 않고 여러 레코드를 동시에 처리할 수 있는 경우를 말한다. 스트림 내 레코드의 예시는 다음과 같다.

스트림 내 레코드 예시
분야레코드 내용
그래픽삼각형의 정점, 법선, 색상 정보
이미지 처리이미지의 단일 픽셀
비디오 인코딩256개의 픽셀로 구성된 데이터의 매크로 블록
무선 신호 처리안테나에서 수신된 샘플 시퀀스



각 레코드에 대해 입력에서 읽고, 연산을 수행하며, 출력에 쓰는 작업이 이루어진다. 여러 개의 입력과 출력을 가질 수 있지만, 임의의 메모리 위치를 읽고 쓰는 것은 일반적으로 허용되지 않는다.

초기 CPU는 한 번에 하나의 연산만 수행하는 Single Instruction, Single Data|단일 명령, 단일 데이터영어(SISD) 방식이었다. 계산량이 급증하면서 순차 계산 모델로는 요구를 충족하기 어려워졌고, 이에 하나의 명령으로 여러 값을 계산하는

그러나 SIMD와 MIMD 방식은 메모리 정렬 문제, 동기화 문제, 병렬성 제약 등 다양한 제약에 부딪혔다. SIMD는 주로 범용 프로세서의 명령어 집합 일부로 구현되는 경우가 많다.

예를 들어, 100개의 4차원 벡터를 더하는 프로그램을 생각해 보자. 가장 단순한 순차 처리 방식은 다음과 같다.



for (int i = 0; i < 100 * 4; i++)

result[i] = source0[i] + source1[i];



이 방식은 덧셈 명령 400번 외에도 루프 제어를 위한 조건 분기, 카운터 증가 등 추가 명령이 실행된다.

SIMD 명령 `vector_sum`을 사용하면 4차원 벡터 계산을 한 번에 수행할 수 있다.



for (int el = 0; el < 100; el++) // 각 벡터에 대해

vector_sum(result[el], source0[el], source1[el]);



4개의 덧셈을 한 번에 처리하므로 덧셈 및 분기 명령 횟수가 1/4로 줄어든다. 하지만 SIMD 레지스터 크기에 의해 병렬성이 제한되어, 이 예시에서는 최대 4배의 속도 향상만 가능하다. AltiVec이나 SSE도 비슷한 한계를 가진다.

스트림 처리 패러다임에 기반한 의사 코드는 다음과 같다.



streamElements 100

streamElementFormat 4 numbers

elementKernel "@arg0+@arg1"

result = kernel(source0, source1)



이 코드는 4개의 숫자를 하나의 요소로 하는 100개의 요소 각각에 덧셈 연산을 수행하는 커널을 적용한다. 언어는 단순해지지만, 커널은 복잡해질 수 있다. 하드웨어 구조에 따라 커널이나 스트림 크기가 제한될 수 있으며, 예를 들어 일반적인 GPU는 배정밀도 부동소수점 연산이나 복잡한 간접 명령을 하드웨어에서 지원하지 않는 경우가 있다.

스트림 프로그래밍 모델의 큰 장점은 '''커널'''에서 비롯된다. 커널은 데이터를 독립적이고 지역적으로 사용하는 방식을 정의하며, 기본적인 데이터 단위를 입출력 양쪽에서 명확히 한다. 이를 통해 하드웨어는 리소스를 효율적으로 할당하고 전역 I/O를 효과적으로 스케줄링할 수 있다. 스트림 프로세서, 특히 GPU의 I/O 동작은 파이프라인화되어 레이턴시 은폐에 기여한다.

데이터의 지역성, 즉 '''커널 지역성'''은 커널 내에서 명시적으로 관리된다. 단일 커널 호출 동안 사용되는 임시 데이터는 지역적인 것으로 간주되어 고속 레지스터에 할당될 수 있다. 이는 활용 가능한 병렬성의 정도와 밀접하게 연관된다.

각 커널 내부에서는 생산-소비 관계를 파악하기 쉽다. 커널 B가 커널 A의 출력을 필요로 한다면, A가 B보다 먼저 완료되어야 한다는 점이 명확하므로 스케줄링 결정을 내리기 용이하다. Imagine 칩의 온보드 스트림 컨트롤러는 커널 종속성 정보를 바탕으로 런타임에 하드웨어 스케줄링을 수행하여, 지연을 최소화하는 비순차적 실행(out-of-order execution영어)을 가능하게 한다. Cell 프로세서도 여러 SPE(Synergistic Processing Element영어) 간 데이터 전송을 통해 유사한 작업을 수행하는 것으로 알려져 있다.

CPU 제조사들이 멀티 코어 및 멀티 스레딩을 강조하고 있지만, 병렬 계산 성능 면에서는 표준 CPU가 스트림 프로세서에 미치기 어려울 것으로 보인다. 스트림 처리는 여러 수준의 병렬성을 활용한다.


  • 두 커널 인스턴스 간의 병렬성 (스레드 수준 병렬성과 유사)
  • 각 커널 내부의 명령 수준 병렬성
  • 태스크 수준 병렬성 (I/O 중첩 등)


수천 개의 커널 인스턴스를 동시에 실행하는 것은 스트림 처리에서는 용이하지만, 동일한 수의 스레드를 생성하는 것은 일반적인 시스템에서는 불가능하다. 이것이 스트림 처리의 강력한 장점이다.

3. 3. 데이터 지역성

'''데이터 지역성'''은 데이터가 한 번 생성된 후 애플리케이션에서 한두 번 읽히고 다시는 참조되지 않는, 특정 유형의 시간적 지역성을 의미한다. 이러한 특성은 특히 디지털 신호 처리나 미디어 처리 애플리케이션에서 흔히 발견된다. 스트림 처리 프로그래밍 모델은 이러한 데이터 지역성을 효과적으로 활용한다. 즉, 커널 함수 내에서 사용되는 중간 데이터나 커널 간에 전달되는 중간 스트림의 지역성을 직접 포착하여 처리 효율을 높인다.

스트림 프로그래밍 모델의 주요 이점 중 하나는 데이터를 독립적이고 지역적으로 사용하는 방식을 정의하는 '''커널'''에서 비롯된다. 커널은 기본적인 데이터 처리 단위를 입력과 출력 측면에서 명확히 정의하며, 이를 통해 하드웨어는 자원을 효율적으로 할당하고 전역 I/O 작업을 효과적으로 스케줄링할 수 있다. 데이터 단위의 명확한 정의는 대량의 읽기 및 쓰기 작업을 최적화하여 캐시와 메모리 버스의 효율성을 크게 향상시킨다.

데이터의 지역성은 커널 내에서도 명시적으로 나타나는데, 이를 커널 지역성이라고 부른다. 이는 단일 커널이 호출될 때 사용되는 수명이 짧은 값들을 식별하는 개념이다. 모든 임시 데이터는 각 커널 호출에 대해 지역적인 것으로 간주되어, 하드웨어와 소프트웨어는 이를 고속 레지스터에 할당하여 처리 속도를 높일 수 있다. 이는 가용한 병렬성의 정도와 밀접하게 연관된다.

또한, 각 커널 내부에서는 개별적인 생산-소비 관계를 파악할 수 있다. 만약 커널 B가 커널 A의 출력을 필요로 한다면, 커널 A는 (적어도 해당 데이터 단위에 대해) 커널 B가 실행되기 전에 완료되어야 한다는 점이 명확해진다. 이는 스케줄링 결정을 단순화한다. 예를 들어, Imagine 칩의 온보드 스트림 컨트롤러는 컴파일러가 제공하는 커널 종속성 정보를 바탕으로 런타임에 커널 로드를 하드웨어에서 수행하여, 지연(stall)을 최소화하는 비순차적 실행(out-of-order execution)을 가능하게 한다. Cell 프로세서 역시 여러 SPE(Synergistic Processing Elements) 간에 데이터를 전송하며 유사한 방식을 사용하는 것으로 알려져 있다. Imagine은 순수한 SIMD 머신인 반면, Cell은 MIMD 머신에 가깝다는 차이가 있다.

데이터 지역성을 활용하는 스트림 처리 방식은 다양한 수준의 병렬성을 효과적으로 관리하는 데 기여한다. 두 커널 인스턴스 간의 병렬성은 스레드 수준 병렬성과 유사하며, 각 커널 내부에서는 명령어 수준 병렬성을 활용할 수 있다. 또한, I/O 작업 중첩과 같은 태스크 수준 병렬성도 가능하다. 스트림 처리 모델은 수천 개의 커널 인스턴스를 동시에 관리할 수 있게 하여 높은 수준의 병렬 처리를 가능하게 한다.

3. 4. 스트림과 커널

스트림 프로세싱의 계산 모델은 '''스트림'''(stream영어)이라고 불리는 입력 데이터 세트의 각 요소에 대해, '''커널'''(kernel영어)이라고 불리는 연산 조작을 적용하는 방식이다. 커널은 스트림에 대해 파이프라인 방식으로 작동하며, 입력 스트림과 연산 후의 출력 스트림은 외부의 메인 메모리가 아닌 프로세서 내의 로컬 스토어(local store)에 저장된다. 이를 통해 커널을 스트림에 여러 번 적용할 경우 메모리 접근 시간을 단축시킬 수 있다.

이론적으로는 여러 개의 커널을 가질 수 있지만, '''유니폼 스트리밍'''(uniform streaming영어) 방식에서는 스트림의 각 요소에 적용되는 커널을 하나만 사용한다. 유니폼 스트리밍은 특히 SIMD(Single Instruction, Multiple Data) 환경에서 스트림 연결을 단순화하여 성능을 크게 향상시킬 수 있다. 또한, 스트림 프로세싱은 비교적 간단한 프로그래밍 모델을 제공하여 C 언어로 개발이 가능하며(어셈블러 불필요), 하드웨어 상에서 최적의 성능을 달성하도록 돕는다.

스트림 프로세싱의 또 다른 중요한 장점은 스트림과 커널의 추상화를 통해 데이터 의존성을 명시적으로 만든다는 점이다. 이는 하드웨어에서 DMA를 작동시키기 위한 런타임 평가 기구 등을 갖출 수 있게 하며, 컴파일러 도구가 칩 상에서 수행하는 관리(예: 스트림 크기 결정 및 할당)를 완전히 자동화하고 최적화할 수 있게 한다. 데이터 의존 관계가 이미 알려져 있기 때문에, 하드웨어 캐시나 DMA의 수동 관리가 필요 없어진다. 이는 일반적인 DSP를 사용할 때 처리 시간의 상당 부분을 차지하는 작업을 불필요하게 만든다. 온칩 메모리("소프트웨어 관리 캐시")의 효율성 덕분에 칩의 다이 크기를 줄일 수 있고, 확보된 공간을 ALU에 더 많이 할당할 수 있다.

예를 들어, 두 배열 `source0`와 `source1`의 각 요소를 더해 `result` 배열에 저장하는 작업을 생각해 보자. 가장 단순한 방법은 다음과 같이 반복문을 사용하는 것이다.



for (int i = 0; i < 100 * 4; i++)

result[i] = source0[i] + source1[i];



이 방식은 덧셈 연산 400회 외에도 반복문 제어를 위한 조건 분기, 카운터 `i` 증가 등 추가적인 명령이 많이 실행된다.

SIMD 명령을 사용하면 여러 데이터 요소를 한 번에 처리할 수 있다. 예를 들어 4차원 벡터 덧셈을 수행하는 `vector_sum` 명령을 사용하면 다음과 같이 코드를 작성할 수 있다 (벡터 차원과 데이터 형식은 생략).



for (int el = 0; el < 100; el++) // 각 벡터에 대해

vector_sum(result[el], source0[el], source1[el]);



4개의 덧셈을 한 번에 수행하므로, 순차 실행 방식에 비해 덧셈 및 조건 분기 명령 횟수가 1/4로 줄어든다. 그러나 SIMD 방식은 레지스터 크기에 의해 병렬성이 제한되어, 이 예에서는 4개 요소 동시 처리 이상으로 성능을 높이기 어렵다. AltiVec이나 SSE 등도 유사한 한계를 가진다.

스트림 프로세싱 패러다임에 기반한 의사 코드는 다음과 같다.

```

streamElements 100

streamElementFormat 4 numbers

elementKernel "@arg0+@arg1"

result = kernel(source0, source1)

```

이 코드는 4개의 숫자를 하나의 요소로 정의하고, 이러한 요소 100개 각각에 대해 덧셈 연산을 수행하는 커널을 적용한다. 언어적으로는 단순해 보이지만, 실제 커널 구현은 복잡해질 수 있다. 예를 들어 루프를 완전히 펼치면 100개의 4-ALU 커널이 필요할 수 있다.

이러한 SIMD/MIMD 모델은 유연한 프로그래밍을 가능하게 하지만, 커널이나 스트림의 크기는 스트림 프로세서 하드웨어의 제약을 받는다. 예를 들어, 일반적인 GPU는 배정밀도 부동소수점 연산이나 복잡한 간접 참조 명령을 하드웨어에서 지원하지 않는 경우가 많다.

스트림 프로그래밍 모델의 큰 장점은 데이터 사용의 '''독립성'''(independence영어)과 '''지역성'''(locality영어)을 정의하는 '''커널'''에서 비롯된다. 커널은 기본적인 데이터 단위를 입력과 출력 양쪽에서 정의하며, 이를 통해 하드웨어는 자원을 효율적으로 할당하고 글로벌 I/O를 효과적으로 스케줄링할 수 있다. 일반적인 프로그래밍 모델에서는 잘 드러나지 않지만, 스트림 프로세서(특히 GPU)의 I/O 동작은 상당히 발전되어 있으며, 종종 파이프라인화되어 칩 구조를 통해 레이턴시(latency) 은폐를 돕는다. 데이터 단위는 일반적으로 커널 내에서 명시적으로 정의되며(예: 구조체 사용 권장), 명확한 입력과 출력을 가진다. 일부 환경(특히 GPU)에서는 출력 형식이 고정되기도 한다. 각 계산 블록을 명확하게 독립적으로 정의함으로써, 대량의 읽기 및 쓰기 연산 시 캐시와 메모리 버스의 효율성이 현저하게 향상된다.

데이터의 지역성 역시 커널에서 명시적으로 드러난다. 이는 '''커널 지역성'''(kernel locality영어)이라고 불리며, 단일 커널 호출 동안 사용되는 임시(temporary) 값들을 식별한다. 모든 임시 데이터는 각 커널 호출에 대해 지역적(local)이라고 가정되므로, 하드웨어와 소프트웨어는 이를 고속 레지스터에 할당하여 성능을 높일 수 있다. 이는 달성 가능한 병렬성의 정도와 밀접하게 관련된다.

각 커널 내부에서는 개별적인 생산-소비 관계를 파악할 수 있다. 커널들이 순차적으로 연결될 경우, 이 관계는 모델 자체에 의해 제공된다. 예를 들어 커널 B가 커널 A의 출력을 필요로 한다면, 커널 B가 실행되기 전에 커널 A가 (적어도 사용될 데이터 단위에 대해서는) 완료되어야 함이 명백하다. 이는 스케줄링 결정을 용이하게 한다. Imagine 칩의 온보드 스트림 컨트롤러 모듈은 컴파일러가 제공하는 커널 종속성 정보를 바탕으로 스코어보드를 유지하며, 런타임에 커널 로드를 하드웨어에서 수행하여 스톨(stall)을 최소화하는 아웃오브오더 실행(out-of-order execution)을 가능하게 한다. 이는 고성능 연산 처리의 새로운 패러다임으로 여겨진다. Cell 프로세서도 여러 SPE(Synergistic Processing Element) 간 데이터 전송 시 유사한 방식을 사용한다고 알려져 있다. 반면, Imagine은 순수한 SIMD 머신으로, 클러스터 간 통신과 커널 실행이 항상 명시적이며, Cell과 같은 MIMD 머신에 비해 실리콘 면적이 작다는 특징이 있다.

CPU 벤더들이 멀티 코어 및 멀티 스레딩을 추진하고 있다. 이 트렌드는 일반 사용자에게 유용할 수 있지만, 표준 CPU가 병렬 계산에서 스트림 프로세서의 성능에 근접할 여지는 없을 것이다.

스트림 프로세싱에서는 여러 수준의 병렬성을 활용할 수 있다.

  • 두 커널 인스턴스의 병렬 실행은 스레드 수준 병렬성(Thread-Level Parallelism, TLP)과 유사하다.
  • 각 커널 내부에서는 명령 수준 병렬성(Instruction-Level Parallelism, ILP)을 활용할 수 있다.
  • 작업 수준 병렬성(Task-Level Parallelism), 예를 들어 오버랩된 I/O 등이 발생할 수 있다.


커널 인스턴스를 수천 개 갖는 것은 쉽지만, 동일한 수의 스레드를 갖는 것은 불가능하다. 이것이 스트림의 힘이다.

4. 프로그래밍 모델

스트림 프로세싱의 프로그래밍 모델은 대규모 데이터 흐름을 효율적으로 처리하기 위한 방법을 다룬다. 이는 데이터 구조를 메모리에 배치하는 방식(데이터 레이아웃)과 데이터를 처리하는 연산 단위(계산 모델)를 중심으로 구성된다.

4. 1. 구조체 배열(AoS)과 배열 구조체(SoA)

SIMD 프로그래밍 모델의 주요 과제 중 하나는 구조체 배열(Array of Structures, AoS)과 배열 구조체(Structure of Arrays, SoA) 문제였다. 프로그래머는 종종 데이터의 논리적 구조를 반영하여 메모리 상에 객체를 표현하는데, 이 과정에서 성능 문제가 발생할 수 있다. 예를 들어, 3차원 공간의 입자 데이터를 표현하기 위해 다음과 같은 구조체를 정의할 수 있다.



// 3차원 공간의 입자 (AoS 예시)

struct particle_t {

float x, y, z; // 위치 좌표

unsigned char color[3]; // 색상 (RGB) - 채널당 8비트

float size; // 크기

// ... 다른 속성들 ...

};



이러한 구조체 여러 개를 메모리에 연속적으로 배치하여 배열을 만드는 방식이 구조체 배열(AoS)이다. 메모리에는 `[입자1(x,y,z,color,size), 입자2(x,y,z,color,size), ...]` 형태로 데이터가 저장된다. 이 방식의 문제점은 특정 속성, 예를 들어 모든 입자의 'x' 좌표에만 접근하여 SIMD 연산을 수행하고자 할 때 발생한다. SIMD 명령어는 보통 메모리 상에 연속적으로 놓인 데이터를 효율적으로 처리하도록 설계되었지만, AoS 방식에서는 각 입자의 'x' 좌표 사이에 다른 속성들(y, z, color, size 등)이 끼어있어 메모리 접근 패턴이 불규칙해진다. 이는 관련 없는 데이터를 메모리에서 읽어와 캐시 효율성을 떨어뜨리고, 데이터 정렬 문제도 야기할 수 있다. 특히 위 예시처럼 'x, y, z' 좌표가 개별 변수로 선언되거나, 'color'처럼 SIMD 유닛(보통 4요소 처리)이 직접 처리하기 어려운 3요소 벡터로 정의되면 SIMD 활용은 더욱 복잡해진다.

이러한 문제를 해결하기 위한 대안으로 배열 구조체(SoA) 방식이 있다. SoA는 각 속성별로 독립적인 배열을 만들고, 구조체는 이 배열들을 가리키는 포인터나 참조를 저장하는 방식이다.



// 배열 구조체 (SoA 예시)

struct particle_t {

float *x, *y, *z; // 각 좌표별 배열 포인터

unsigned char *colorRed, *colorBlue, *colorGreen; // 색상 채널별 배열 포인터

float *size; // 크기 배열 포인터

};



SoA 방식에서는 `[입자1_x, 입자2_x, 입자3_x, ...]`, `[입자1_y, 입자2_y, 입자3_y, ...]` 와 같이 동일한 속성의 데이터가 메모리에 연속적으로 저장된다. 따라서 특정 속성에 대한 SIMD 연산을 매우 효율적으로 수행할 수 있다. 하지만 단점도 존재한다. 만약 한 객체의 여러 속성(예: 입자1의 x, y, z 좌표 모두)에 동시에 접근해야 할 경우, 각 속성 배열이 메모리 상에 서로 멀리 떨어져 있을 수 있어 캐시 미스가 발생할 가능성이 커진다. 또한, 각 속성 배열을 개별적으로 할당하고 관리해야 하므로 메모리 관리가 더 복잡해지며, 정렬 및 패딩(padding)으로 인해 메모리 사용량이 증가할 수도 있다.

스트림 프로세서는 이러한 AoS/SoA 문제를 해결하기 위해 구조체 사용을 권장하면서도, 데이터 접근의 유연성과 효율성을 높이는 방식을 채택한다. 애플리케이션 관점에서는 다양한 속성을 유연하게 정의할 수 있다. 예를 들어 GPU에서는 여러 속성(최소 16개 이상)을 정의하고, 각 속성에 대해 구성 요소의 수와 데이터 형식(주로 기본 데이터 타입)을 지정할 수 있다. 또한, 메모리 블록에 속성을 할당할 때, 동일 속성의 연속된 요소 간의 간격(스트라이드, stride)을 정의하여 데이터를 인터리빙(interleaving)하는 것도 가능하다.

GPU가 스트림 처리를 시작하면, 필요한 다양한 속성들을 하나의 매개변수 집합(개념적으로 구조체나 특별한 전역 변수처럼 작동)으로 수집(gather)하여 커널 연산을 수행한다. 연산이 완료된 후에는 그 결과를 다음 처리 단계나 최종 결과 저장을 위해 특정 메모리 영역에 분산(scatter)시킨다. 이러한 접근 방식은 애플리케이션 개발자에게 데이터 구조 정의의 유연성을 제공하는 동시에, 스트림 프로세서 하드웨어가 데이터를 매우 질서정연하고 효율적으로 처리할 수 있도록 지원한다.

4. 2. 계산 모델

스트림 프로세싱의 계산 모델(Model of Computation|MoCeng)은 ''스트림''(stream)이라 불리는 입력 데이터 세트의 각 요소에 대해, ''커널''(kernel)이라는 연산 조작을 적용하는 방식이다.[1] 스트림에 대해 커널은 파이프라인 방식으로 작동하며, 입력 스트림과 연산 후의 출력 스트림은 외부의 메인 메모리가 아닌 프로세서 내의 로컬 저장소에 저장될 수 있다. 이는 커널을 스트림에 여러 번 적용할 때 메모리 접근 시간을 단축시키는 효과를 가져온다.[1] 스트리밍 애플리케이션을 위한 고급 언어 지정 방식으로는 데이터 흐름 모델과 프로세스 기반 모델이 널리 사용된다.[1]

스트림과 커널의 추상화는 데이터 의존성을 명시적으로 드러내므로, 컴파일러 도구가 스트림 크기 결정이나 할당 같은 칩 상의 관리를 자동화하고 최적화하기 용이하다.[1] 이는 하드웨어 캐시DMA의 수동 관리가 필요 없음을 의미하며, 일반적인 DSP 사용 시 많은 처리 시간을 소모하는 작업을 줄여준다.[1] 또한, 온칩 메모리("소프트웨어 관리 캐시")의 효율성 덕분에 다이 크기를 줄이고 ALU에 더 많은 공간을 할당할 수 있게 된다.[1]

초기 CPU는 한 번에 하나의 연산만 처리하는 SISD(Single Instruction, Single Data) 방식이었으나, 계산량 증가에 따라 하나의 명령으로 여러 데이터를 처리하는 SIMD(Single Instruction, Multiple Data) 방식이 고안되었다.[1] 이후 MIMD(Multiple Instruction, Multiple Data) 병렬성도 도입되었지만,[1] 이 방식들은 메모리 정렬, 동기화, 병렬성 제약 등 실제 적용에 어려움이 있었다.[1]

SIMD 프로그래밍 모델의 주요 과제 중 하나는 구조체 배열(Array of Structures, AoS)배열의 구조체(Structure of Arrays, SoA) 문제이다.[1] 프로그래머는 종종 데이터의 논리적 의미를 반영하여 메모리 상에 객체 표현을 만드는데, 예를 들어 3차원 공간의 입자 데이터를 다음과 같이 C 스타일 구조체로 정의할 수 있다.



// 구조체 배열 (AoS) 예시

struct particle_t {

float x, y, z; // 위치

unsigned char color[3]; // 색상 (RGB)

float size; // 크기

// ... 기타 속성 ...

};



이러한 구조체들을 배열로 만들면 메모리에는 각 입자의 모든 속성(x, y, z, color, size 등)이 묶여서 연속적으로 배치되는 AoS 형태가 된다.[1] 이 방식은 특정 속성(예: 모든 입자의 x 좌표)만 순차적으로 접근해야 할 때, 관련 없는 다른 속성 데이터(y, z, color 등)를 건너뛰어야 하므로 CPU 캐시 효율성이 떨어지고 SIMD 명령어 활용이 어렵다. 특히 SIMD 명령어는 데이터가 메모리 상에 연속적으로 나열되고 정렬되어 있기를 기대하기 때문이다.[1] 또한 위 예시에서 color나 xyz 좌표는 3요소 벡터인데, 일반적인 SIMD는 4요소 연산을 주로 지원하므로 비효율이 발생할 수 있다.[1]

이 문제를 해결하기 위해 데이터 구조를 속성별 배열로 구성하는 SoA 방식이 있다. 개념적으로는 다음과 같이 각 속성별 배열을 포인터로 관리하는 형태이다.



// 배열의 구조체 (SoA) 예시 (개념적 표현)

struct particle_t {

float *x, *y, *z; // 각 속성별 배열을 가리키는 포인터

unsigned char *colorRed, *colorBlue, *colorGreen;

float *size;

};



SoA 방식에서는 각 속성(모든 x 좌표, 모든 y 좌표 등)이 메모리 상에 연속적으로 배치되므로 SIMD 처리에는 유리하다.[1] 하지만 객체 하나의 여러 속성을 동시에 접근해야 할 경우, 각 속성 데이터가 메모리 상에 멀리 떨어져 있어 캐시 미스가 발생하기 쉽고, 메모리 관리가 더 복잡해지는 단점이 있다.[1]

스트림 프로세서는 이러한 AoS/SoA 문제를 해결하기 위해 유연한 데이터 처리 방식을 제공한다. GPU를 예로 들면, 애플리케이션은 여러 속성(attributeeng)을 정의하고 각 속성의 데이터 타입과 컴포넌트 수를 지정할 수 있다.[1] 데이터는 메모리 블록에 할당되며, 요소 간의 간격(strideeng)을 정의하여 인터리빙된 데이터 구조도 지원한다.[1] GPU는 스트림 처리 시 필요한 속성들을 하나의 파라미터 세트로 수집(gathereng)하여 커널 연산을 수행하고, 그 결과를 메모리의 특정 영역에 분산(scattereng)하여 저장한다.[1] 이는 애플리케이션 개발자에게는 유연성을 제공하면서도, 하드웨어는 정돈된 방식으로 데이터를 효율적으로 처리할 수 있게 한다.[1]

최근의 스트림 처리 프레임워크는 실제 스트림과 유사한 FIFO 인터페이스를 제공하여 데이터를 구조화한다. 이 추상화는 데이터 의존성을 암시적으로 명시하면서 런타임이나 하드웨어가 효율적인 계산을 위해 이 정보를 활용할 수 있게 한다.[1] C++ 기반의 스트림 처리 라이브러리 중 하나인 RaftLib는 C++ 스트림 연산자를 사용하여 독립적인 컴퓨트 커널데이터 흐름 그래프로 연결하는 방식을 사용한다. 예를 들어, "Hello World"를 출력하는 간단한 파이프라인은 다음과 같이 구성할 수 있다.



#include

#include

#include

#include

// "Hello World" 문자열을 생성하는 커널

class hi : public raft::kernel

{

public:

hi() : raft::kernel()

{

output.addPort("0"); // 출력 포트 정의

}

virtual raft::kstatus run()

{

output["0"].push(std::string("Hello World\n")); // 데이터 출력

return raft::stop; // 커널 종료

}

};

int main(int argc, char **argv)

{

raft::print< std::string > p; // 문자열을 출력하는 내장 커널

hi hello; // 위에서 정의한 hi 커널

raft::map m; // 커널들을 연결할 맵 객체

// hello 커널의 출력을 p 커널의 입력으로 연결 (데이터 흐름 정의)

m += hello >> p;

m.exe(); // 정의된 파이프라인 실행

return EXIT_SUCCESS;

}



이 예시에서는 `hello` 커널이 생성한 데이터가 `p` 커널로 흘러가 출력된다.[1]

스트림 처리 모델의 효율성을 이해하기 위해 100개의 4차원 벡터 덧셈을 예로 들어보자.

# 순차 처리: 각 요소를 하나씩 더한다.



for (int i = 0; i < 100 * 4; i++) {

result[i] = source0[i] + source1[i];

}



이 방식은 400번의 덧셈 외에 루프 제어를 위한 추가 명령이 많이 필요하다.[1]

# SIMD 처리: 4차원 벡터 연산을 한 번에 수행하는 명령어를 사용한다.



// vector_sum은 4개 요소 덧셈을 한 번에 처리한다고 가정

for (int el = 0; el < 100; el++) {

vector_sum(result[el], source0[el], source1[el]);

}



덧셈 및 루프 제어 명령 횟수가 줄어들지만, SIMD 레지스터 폭(예: 4개 요소)에 의해 병렬성이 제한된다.[1]

# 스트림 처리 (개념적 표현):

streamElements 100 // 스트림 요소 개수 정의

streamElementFormat 4 numbers // 요소 형식 정의 (4개의 숫자)

elementKernel "@arg0+@arg1" // 각 요소에 적용할 커널 정의 (덧셈)

result = kernel(source0, source1) // 커널 적용 실행



이 모델은 하드웨어가 허용하는 한 높은 병렬성(이론적으로 100개의 4-ALU 커널 동시 실행 가능)을 달성할 잠재력을 가지며, 프로그래밍 모델을 단순화한다.[1] 다만, 커널이나 스트림 크기는 실제 하드웨어(예: GPU)의 제약을 받는다.[1]

5. 하드웨어 아키텍처

스트림 프로세싱에 대한 초기 연구는 스탠퍼드 대학교를 중심으로 이루어졌다. 2005년 9월 12일 경에는 관련 자료가 부족했지만, 스탠퍼드 대학은 Stanford Shading language를 시작으로, 독립형 스트림 프로세서인 Imagine 프로젝트를 진행하며 스트림 프로세싱의 가능성을 탐구했다. 이러한 연구 성과를 바탕으로 스트림 기반 슈퍼컴퓨터 개발을 목표로 하는 Merrimac 프로젝트가 시작되어 연구가 계속 진행되었다.

한편, AT&T 등에서는 스트림 처리 개념을 확장한 프로세서가 널리 사용되면서 GPU의 성능과 기능이 빠르게 발전했다고 보고 있다.

5. 1. 범용 프로세서와의 비교

CPU와 같은 범용 프로세서는 성능 향상에 비해 외부 메모리 대역폭 증가가 상대적으로 느렸기 때문에, 메모리 접근 최적화와 메모리 지연 시간을 숨기기 위한 다양한 계층 구조에 많은 다이 영역을 할애해왔다.[5][6] 이러한 격차가 커짐에 따라, 실제 연산을 수행하는 ALU 자체에 할당되는 다이 영역은 전체의 10% 미만으로 추정될 정도로, 메모리 관련 구조가 차지하는 비중이 커졌다.

반면, 스트림 프로세서는 프로그래밍 모델의 특성 덕분에 이러한 관리(계산을 직접 수행하지 않는 부분)에 필요한 트랜지스터의 양이 훨씬 적다. 이는 더 많은 다이 영역을 실제 연산 유닛에 할당하여 효율성을 높일 수 있게 한다.

메모리 시스템에서도 차이가 나타난다. 스트림 프로세서는 일반적으로 빠르고 효율적인 독자적인 메모리 버스 구조를 가진다. 크로스바 스위치가 흔히 사용되며, 중급 모델에서는 128비트, 고급 모델에서는 256비트 폭의 버스를 통해 대용량 메모리에 접근하는 경우가 많다. 이는 과거 펜티엄이나 애슬론 64와 같은 표준 프로세서들이 주로 64비트 폭의 단일 데이터 버스를 가졌던 것과 비교된다.

또한, 스트림 프로세서의 메모리 접근 패턴은 예측 가능성이 높다. 커널 호출 시 배열의 메모리 배치가 고정되고, 포인터 간접 참조도 특정 메모리 영역 내에서 이루어지도록 제한되는 경우가 많다. 실행 유닛(ALU 클러스터)의 SIMD적 특성으로 인해 대량의 읽기/쓰기 작업이 발생하므로, 메모리는 낮은 지연 시간(low latency)보다는 높은 대역폭(high bandwidth)에 최적화되어 설계된다. 이는 RambusDDR SDRAM의 설계 목표 차이와 유사한 점이다. 이러한 최적화는 효율적인 메모리 버스 조정(negotiation)을 가능하게 한다.

이러한 구조적 차이는 성능으로 이어진다. 스트림 프로세서는 효율적인 메모리 접근과 높은 수준의 병렬 처리를 통해 특정 작업에서 범용 프로세서 대비 10배 이상의 성능 향상을 쉽게 달성할 수 있다.[6] 반면, 범용 프로세서에 스트림 처리 방식을 적용하더라도 약 1.5배 정도의 속도 향상에 그칠 수 있다는 지적도 있다.[5]

스트림 프로세서 내부적으로는 데이터 관리를 위해 스트림 레지스터 파일(SRF)과 로컬 레지스터 파일(LRF) 같은 구조를 활용한다. SRF는 스트림 데이터를 외부 메모리로 대량 전송하기 전에 저장하는, 여러 ALU 클러스터 간에 공유되는 대규모 캐시와 유사한 역할을 한다. LRF는 각 ALU에 할당된 로컬 레지스터이다. 이 3계층 데이터 접근 방식은 임시 데이터를 저속 메모리에서 분리하여 효율성을 높이고 전력 소모를 줄이는 데 기여한다. 특히, 스탠퍼드의 Imagine 칩 연구에서는 프로그래밍 모델을 통해 데이터 의존성이 명확해지므로, 컴파일러가 SRF 패킹이나 DMA 전송과 같은 메모리 관리를 자동화하고 최적화할 수 있음을 보여주었다. 이는 개발자가 수동으로 캐시나 DMA를 관리하는 데 드는 노력을 크게 줄여준다.

5. 2. 내부 구조

일반적인 CPU는 성능 향상에 비해 외부 메모리 대역폭 증가가 상대적으로 느리기 때문에, 메모리 접근 지연 시간을 줄이기 위해 여러 계층의 캐시 메모리를 사용하는 등 복잡한 최적화 기법을 사용한다. 이 과정에서 실제 연산을 수행하는 ALU보다는 메모리 관련 회로에 더 많은 칩 면적이 할애되기도 한다 (일부 추정에서는 ALU 비중이 10% 미만이다). 스트림 프로세서 역시 유사한 메모리 계층 구조를 가지지만, 스트림 프로그래밍 모델 자체가 데이터 흐름을 명확하게 정의하므로 메모리 관리에 필요한 하드웨어 복잡성이 상대적으로 낮다.

스트림 프로세서는 주로 GPU와 같이 특정 작업(그래픽 처리, 병렬 연산 등)에 특화된 형태로 사용되며, 시스템의 메인 CPU는 운영체제 실행, 시스템 자원 관리 등 일반적인 작업을 담당한다. 스트림 프로세서는 고속의 전용 메모리 버스를 통해 대량의 데이터를 처리하는데, 크로스바 스위치와 같은 병렬 데이터 전송 구조가 널리 사용된다. 메모리 버스의 폭(데이터 전송 통로의 크기)은 제품 등급에 따라 64비트, 128비트, 256비트 등으로 다양하다. 이는 과거 펜티엄이나 애슬론 64와 같은 일반 CPU가 주로 64비트 단일 버스를 사용했던 것과 대조적이다.

스트림 프로세서의 메모리 접근은 일반 CPU보다 예측하기 쉽다. 데이터는 주로 배열 형태로 처리되며, 특정 연산(커널)을 수행할 때 메모리 배치가 고정된다. 복잡한 포인터 연산보다는 '간접 참조 체인'(indirection chaineng)과 같이 데이터 흐름이 비교적 명확한 방식이 사용되며, 최종적으로는 스트림 내부의 특정 메모리 영역에 접근하는 것이 보장된다. 또한, 스트림 프로세서는 SIMD 방식으로 동작하여 한 번에 많은 데이터를 처리하므로, 메모리 시스템은 접근 속도(지연 시간)보다는 데이터 전송량(대역폭)에 중점을 두고 최적화된다. 이는 고대역폭 메모리 기술(예: GDDR)이 GPU에 주로 사용되는 이유이기도 하다.

스트림 프로세싱 작업의 상당 부분(약 90% 추정)은 칩 내부에서 완료되며, 외부 메모리와의 데이터 교환은 최소화된다(전체 데이터의 약 1% 정도만 저장). 이는 연산(커널) 수행에 필요한 임시 데이터와 데이터 간의 의존 관계를 프로그래밍 모델 단계에서 명확히 함으로써 가능하다.

스트림 프로세서의 핵심적인 내부 구조 요소는 다음과 같다.

  • 스트림 레지스터 파일 (SRF, Stream Register Fileeng): 여러 ALU 클러스터들이 공유하는 대규모 온칩 메모리이다. 외부 메모리와 ALU 클러스터 사이의 데이터 전송을 위한 대규모 캐시 역할을 수행하며, 스트림 데이터를 임시로 저장한다. 스탠퍼드 대학교의 Imagine 칩 연구를 통해, 컴파일러가 데이터 흐름과 의존성을 분석하여 SRF 사용 및 DMA 전송을 자동으로 최적화하는 기술이 제시되었다. 이를 통해 개발자가 수동으로 메모리 관리를 최적화하는 부담을 줄이고 효율성을 높일 수 있다.

  • ALU 클러스터: 실제 연산을 수행하는 ALU들의 묶음이다. 스트림 프로세서는 여러 개의 ALU 클러스터를 가질 수 있다. 클러스터 간의 데이터 통신은 상대적으로 적고, 클러스터 내부의 ALU 간 통신은 빈번하게 발생한다고 가정하여 설계된다.

  • 로컬 레지스터 파일 (LRF, Local Register Fileeng): 각 ALU에 직접 연결된 소규모 고속 메모리이다. ALU가 연산에 사용할 데이터나 중간 결과를 저장하는 로컬 레지스터 역할을 한다.


이러한 요소들은 LRF (ALU 로컬) → SRF (클러스터 공유 캐시) → 외부 메모리로 이어지는 3단계 데이터 접근 구조를 형성한다. 이 구조는 연산에 필요한 데이터를 최대한 ALU 가까이에 두어 느린 외부 메모리 접근을 최소화함으로써, 칩의 연산 효율성을 높이고 전력 소비를 줄이는 데 기여한다.

6. 응용 분야

스트림 프로세싱은 본질적으로 데이터 중심 모델에 의해 구동되며, 이는 전통적인 디지털 신호 처리 (DSP)나 GPU 유형의 애플리케이션(예: 이미지, 비디오 및 디지털 신호 처리)에는 매우 적합하다. 반면, 데이터베이스와 같이 무작위적인 데이터 접근이 잦은 일반적인 처리 작업에는 상대적으로 덜 적합하다. 스트림 프로세싱 모델은 유연성을 일부 제한하는 대신, 더 쉽고 빠르며 효율적인 실행을 가능하게 한다. 상황에 따라 프로세서 설계는 최대 효율성을 위해 최적화되거나, 유연성을 확보하는 방향으로 절충될 수 있다.

스트림 프로세싱은 특히 다음 세 가지 특성을 나타내는 애플리케이션에 효과적이다.


  • 계산 집약도: 입출력(I/O) 또는 전역 메모리 참조당 수행되는 산술 연산의 수를 의미한다. 오늘날 많은 신호 처리 애플리케이션에서 이 비율은 50:1을 훨씬 넘으며, 알고리즘 복잡성이 증가함에 따라 더욱 높아지는 경향이 있다.
  • 데이터 병렬성: 동일한 함수(커널)가 입력 스트림의 모든 레코드에 적용될 수 있으며, 이전 레코드의 결과를 기다리지 않고 여러 레코드를 동시에 처리할 수 있는 경우를 말한다.
  • 데이터 지역성: 데이터가 생성된 후 애플리케이션 내에서 한두 번만 읽히고 다시 참조되지 않는 특성이다. 이는 신호 및 미디어 처리 애플리케이션에서 흔히 볼 수 있는 시간적 지역성의 한 형태로, 스트림 처리 프로그래밍 모델은 커널 간 전달되는 중간 스트림이나 커널 함수 내의 중간 데이터를 통해 이러한 지역성을 직접 활용할 수 있다.

6. 1. 예시

스트림 내 레코드의 예는 다음과 같다.

  • 그래픽 처리: 각 레코드는 삼각형의 정점, 법선, 색상 정보일 수 있다.
  • 이미지 처리: 각 레코드는 이미지의 단일 픽셀일 수 있다.
  • 비디오 인코딩: 각 레코드는 256개의 픽셀로 구성된 데이터의 매크로 블록일 수 있다.
  • 무선 신호 처리: 각 레코드는 안테나에서 수신된 샘플 시퀀스일 수 있다.


각 레코드에 대해 입력에서 읽고, 연산을 수행하고, 출력에 쓸 수 있다. 여러 개의 입력과 여러 개의 출력을 가질 수 있지만, 임의의 메모리 위치를 읽고 쓰는 것은 일반적으로 허용되지 않는다.

다음은 연속적인 SQL 쿼리를 사용하여 데이터 스트림을 처리하는 예시이다. 이 쿼리는 타임스탬프와 윈도우 기간을 기반으로 도착하는 데이터를 지속적으로 처리한다. 아래 코드는 주식 주문(Orders)과 결과적인 주식 거래(Trades)라는 두 데이터 스트림을 결합하여, 주문이 체결된 후 1초 이내에 거래와 일치하는 모든 주문의 스트림을 출력한다. 출력 스트림은 주문 스트림의 타임스탬프를 기준으로 정렬된다.

: SELECT DataStream

: Orders.TimeStamp, Orders.orderId, Orders.ticker,

: Orders.amount, Trade.amount

: FROM Orders

: JOIN Trades OVER (RANGE INTERVAL '1' SECOND FOLLOWING)

: ON Orders.orderId = Trades.orderId;

또 다른 예시는 이벤트 스트림 내에서 특정 패턴을 감지하는 것이다. 예를 들어, 교회 종소리, 턱시도나 모닝 수트를 입은 남성의 등장, 흰색 드레스를 입은 여성, 공중에 날리는 쌀과 같은 개별적인 외부 "이벤트"들의 흐름 속에서 '결혼식'이라는 복합 이벤트를 추론할 수 있다. 아래는 이러한 상황을 나타내는 의사 코드 예시이다.

: WHEN Person.Gender EQUALS "man" AND Person.Clothes EQUALS "tuxedo"

: FOLLOWED-BY

: Person.Clothes EQUALS "gown" AND

: (Church_Bell OR Rice_Flying)

: WITHIN 2 hours

: ACTION Wedding

7. 대표적인 스트림 프로세서

스트림 프로세싱 기술은 다양한 하드웨어 아키텍처를 통해 구현되었다. 대표적인 스트림 프로세서로는 다음과 같은 것들이 있다.


  • '''Imagine''': 스탠퍼드 대학교에서 빌 댈리 교수가 주도한 초기 스트림 프로세싱 연구 프로젝트이다.[10] 에너지 효율적인 고성능 아키텍처를 목표로 개발되었다.
  • '''Merrimac''': Imagine과 함께 스탠퍼드 대학교에서 진행된 프로젝트로, 스트림 아키텍처 기반의 슈퍼컴퓨터 개발을 목표로 했다.[11]
  • '''GPU (Graphics Processing Unit)''': AMD와 NVIDIA 등이 개발하는 가장 대중적인 스트림 프로세서이다. 초기에는 그래픽 처리에 국한되었으나, 점차 GPGPU(범용 GPU 컴퓨팅) 기능을 지원하며 활용 범위가 넓어졌다.
  • '''Cell Broadband Engine''': 소니, 도시바, IBM이 공동 개발한 프로세서 아키텍처이다. 플레이스테이션 3의 메인 CPU로 사용되었으며, 특정 프로그래밍 방식을 통해 스트림 프로세서처럼 활용될 수 있다.

7. 1. Imagine

스탠퍼드 대학교의 빌 댈리 교수가 이끈 스트림 프로세싱 프로젝트 '''Imagine'''[10]은 1996년에 처음 구상되었다.[10] 이 프로젝트는 1999년에 시작된 스탠퍼드 실시간 프로그래밍 가능 셰이딩 프로젝트와도 연관이 있다.[7] Imagine은 빠르고 에너지 효율이 높은 유연한 아키텍처를 목표로 개발되었다.[10]

프로젝트는 아키텍처 설계, 소프트웨어 도구 개발, VLSI 구현 및 개발 보드 제작을 포함했으며[10], DARPA, 인텔, 텍사스 인스트루먼트로부터 자금을 지원받았다.[10] 2002년에는 Imagine 프로토타입 칩이 개발되었고[8], 이 첫 번째 실리콘은 코어 소비 전력 1.6W로 3.5 GFLOPS의 성능을 달성하며 높은 에너지 효율성을 보여주었다.

Imagine 프로젝트의 기술은 이후 스트림 프로세서사(Stream Processors, Inc)로 분사되어 '''Storm-1''' 제품군으로 상업화되었으며, 이는 ISSCC 2007 기조 강연에서 발표되었다.

7. 2. Merrimac

스탠퍼드 대학교에서 진행한 또 다른 스트림 프로세싱 프로젝트로, 빌 댈리 교수가 이끈 Imagine 프로젝트와 함께 진행되었다.[11] Merrimac은 스트림 기반 슈퍼컴퓨터 개발을 목표로 하였다. 이 프로젝트는 스트림 아키텍처와 고급 상호 연결 네트워크를 사용하여, 동일한 기술로 구축된 클러스터 기반 과학 컴퓨터보다 단위 비용당 더 높은 성능을 제공하는 것을 추구했다.

Merrimac 프로젝트는 2004년까지 진행되었으며,[9] 2005년 9월 기준으로도 관련 연구가 계속 진행되고 있었다. 당시 스트림 프로세싱에 대한 자료가 부족했음에도 불구하고, 스탠퍼드는 Imagine에 이어 Merrimac과 같은 대규모 프로젝트를 통해 스트림 처리 패러다임의 가능성을 탐구했다.

7. 3. Graphics Processing Unit (GPU)

그래픽 처리 장치(GPU)는 주로 AMD와 NVIDIA에서 설계하는 널리 사용되는 소비자용 스트림 프로세서이다. 개인용 컴퓨터에 탑재되는 GPU는 그래픽 처리뿐만 아니라 범용 스트림 프로세싱 용도(GPGPU)로도 활용 가능하다.

GPU의 스트림 프로세싱 지원은 세대에 따라 발전해왔다.

  • '''R2xx/NV2x 이전''': 스트림 프로세싱에 대한 명시적인 지원이 없었다. 커널 연산은 API에 숨겨져 있었고 일반적인 사용에는 유연성이 부족했다.
  • '''R2xx/NV2x''': 프로그래머가 커널 스트림 연산을 명시적으로 제어할 수 있게 되었지만, 정점 처리에 한정되었다(프래그먼트 처리는 이전 방식 사용). 분기 지원이 없어 유연성이 제한적이었으나, 특정 알고리즘(예: 저정밀도 유체 시뮬레이션) 실행은 가능했다.
  • '''R3xx/NV4x''': 유연한 분기 지원이 추가되었지만, 실행할 연산 수, 재귀 깊이, 배열 조작 등에 여전히 제한이 있었다.
  • '''R8xx''': 추가/소비 버퍼 및 원자적 연산을 지원하며, 이 세대가 최첨단 기술에 해당한다.


고성능 컴퓨팅(HPC) 시장을 겨냥한 제품군으로는 AMD 파이어스트림과 엔비디아 테슬라 브랜드가 있다.

주요 GPU 제조사와 기술은 다음과 같다.

  • '''NVIDIA''': NVIDIA 지포스, NVIDIA 쿼드로, NVIDIA 테슬라 등의 제품군이 있다. G80 아키텍처 이후부터 스트림 프로세싱 개발 환경인 CUDA를 사용할 수 있게 되었다.
  • '''AMD''': AMD 라데온, AMD 파이어프로, AMD 파이어스트림 등의 제품군이 있다. R6xx 아키텍처에서 배정밀도 부동소수점 연산을 지원하기 시작했으며, R7xx (RV770PRO) 기반 제품은 단일 칩으로 세계 최초 1TFLOPS 성능을 달성했다.
  • '''S3 그래픽스''' (과거): S3 크롬 제품군의 Chrome 400 / 500 시리즈에서 OpenCL 1.0을 지원하여 GPGPU 활용 가능성을 열었으나, 현재는 소비자용 GPU 시장에서 철수했다.

7. 4. Cell Broadband Engine

소니 컴퓨터 엔터테인먼트, 도시바, IBM이 공동으로 개발한 Cell은 적절한 소프트웨어 지원 하에 스트림 프로세서처럼 동작할 수 있는 하드웨어 아키텍처이다. Cell은 제어 프로세서 역할을 하는 PPE(Power Processing Element, IBM PowerPC 기반)와 여러 개의 SIMD 코프로세서인 SPE(Synergistic Processor Element)로 구성된다. 각 SPE는 독립적인 프로그램 카운터와 명령어 및 데이터를 위한 256KiB 크기의 로컬 스토어를 가지며, 고속 링 버스를 통해 프로세서 간 통신이 이루어진다. 이러한 구조는 Cell을 실질적인 MIMD 머신으로 기능하게 한다.

네이티브 프로그래밍 모델에서는 프로그래머가 모든 DMA 및 프로그램 스케줄링을 직접 관리해야 한다. 로컬 메모리가 제한적이기 때문에, 메모리 사용량이 적거나 스트림 프로그래밍 모델을 따르는 프로그램만이 이 아키텍처를 효과적으로 활용할 수 있다. 적절한 알고리즘을 사용하면 Cell의 성능은 순수한 스트림 프로세서에 필적할 수 있지만, 이를 위해서는 알고리즘과 소프트웨어의 완전한 재설계가 거의 필수적으로 필요하다.

플레이스테이션 3는 메인 CPU로 Cell을 탑재하여 스트림 프로세서 역할을 수행하도록 했는데, 이는 일반적인 PC 아키텍처와는 다른 주요 특징이다.

8. 스트림 프로그래밍 언어 및 라이브러리

대부분의 스트림 프로세서 프로그래밍 언어는 Java, C 또는 C++에서 시작하여 응용 프로그램 개발자가 커널 및/또는 스트림에 태그를 지정할 수 있도록 특정 지침을 추가한다. 이는 또한 어느 정도까지 스트림 프로그래밍 언어로 간주될 수 있는 대부분의 셰이딩 언어에도 적용된다. 많은 병렬 논리 프로그래밍 언어도 스트림을 사용하여 병렬 계산을 수행한다.

스트림 프로그래밍 언어 및 라이브러리는 비상업적 목적과 상업적 목적으로 개발된 것들이 있다.
비상업적 언어 및 라이브러리


  • Ateji PX Free Edition: JVM에서 스트림 프로그래밍, 액터 모델 및 MapReduce 알고리즘을 간단하게 표현할 수 있도록 지원한다.
  • Auto-Pipe (워싱턴 대학교 세인트루이스): 이기종 시스템(CPU, GPGPU, FPGA)용 스트리밍 응용 프로그램 개발 환경이다. C, C++, Java, Verilog, VHDL, CUDA 등을 사용하며, 여러 머신 간 TCP 연결 조정도 처리한다.
  • ACOTES 프로그래밍 모델 (카탈루냐 공과대학교): OpenMP 기반 언어이다.
  • BeepBeep (UQAC): 간단하고 가벼운 Java 기반 이벤트 스트림 처리 라이브러리이다.
  • 스탠퍼드 대학교Brook 언어.
  • CAL 액터 언어: 데이터 객체(토큰)의 입력 스트림을 출력 스트림으로 변환하는 상태 연산자인 데이터 흐름 액터를 작성하기 위한 고급 프로그래밍 언어이다.
  • Cal2Many (스웨덴 할름스타드 대학교): CAL 코드를 입력으로 받아 순차 C, 병렬 C, ajava & astruct 등 다양한 대상별 언어를 생성하는 코드 생성 프레임워크이다.
  • DUP 언어 (뮌헨 공과대학교, 덴버 대학교).
  • HSTREAM: 이기종 스트림 컴퓨팅을 위한 지침 기반 언어 확장이다.[12]
  • RaftLib (워싱턴 대학교 세인트루이스): 오픈 소스 C++ 스트림 처리 템플릿 라이브러리이다.
  • SPar (리오 그란데 도 술 가톨릭 대학교): 스트림 병렬성을 표현하기 위한 C++ 도메인 특정 언어이다.
  • 워털루 대학교Sh 라이브러리.
  • 오픈 소스 Shallows 프로젝트.
  • S-Net (허트퍼드셔 대학교): 조정과 알고리즘 프로그래밍을 분리하는 조정 언어이다.
  • MIT의 StreamIt.
  • Siddhi (WSO2).
  • WaveScript (MIT): 기능적 스트림 처리 언어이다.
  • 함수형 반응형 프로그래밍: 광범위한 의미에서 스트림 처리로 간주될 수 있다.
  • Concurrent Prolog
  • GHC
  • KL1
  • PARLOG
  • Strand

상업적 구현상업적 구현은 범용이거나 특정 벤더의 하드웨어에 연결되어 있다.

  • 범용 언어
  • Jacket (AccelerEyes): MATLAB용 GPU 엔진의 상업화 버전이다.
  • Ateji PX: 스트림 프로그래밍, 액터 모델 및 MapReduce 알고리즘을 간단하게 표현할 수 있는 Java 확장이다.
  • Embiot (Telchemy): 가벼운 임베디드 스트리밍 분석 에이전트이다.
  • Floodgate: PlayStation 3, Xbox360, Wii 및 PC용 Gamebryo 게임 엔진과 함께 제공되는 스트림 프로세서이다.
  • OpenHMPP: Many-Core 프로그래밍의 "지침" 비전을 제시한다.
  • PeakStream[13]: Brook 프로젝트의 스핀아웃으로, 2007년 6월 구글에 인수되었다.[17]
  • IBM Spade: 스트림 처리 응용 선언 엔진(Stream Processing Application Declarative Engine)이다.
  • RapidMind: Sh의 상업화 버전으로, 2009년 8월 인텔에 인수되었다.
  • TStreams[14][15]: 휴렛 팩커드 케임브리지 연구소에서 개발되었다.

  • 벤더별 언어
  • Brook+ (AMD/ATI): AMD 하드웨어에 최적화된 Brook 구현이다. ATI Stream, Close to Metal(CTM)도 관련 기술이다.
  • CUDA (Compute Unified Device Architecture): 엔비디아에서 제공한다.
  • 인텔 Ct: 처리량 컴퓨팅용 C 언어이다.
  • StreamC (스트림 프로세서, Inc): 스탠퍼드 대학교의 Imagine 작업을 상업화한 것이다.

이벤트 기반 처리

  • Apama (소프트웨어 AG): 결합된 복합 이벤트 처리 및 스트림 처리 엔진이다.
  • Wallaroo
  • WSO2 스트림 프로세서 (WSO2)
  • 아파치 NiFi

배치 파일 기반 처리(실제 스트림 처리의 일부를 에뮬레이트하지만 일반적으로 성능 특성이 다를 수 있다)
연속 연산자 스트림 처리

  • 아파치 플링크
  • Walmartlabs Mupd8[16]
  • 이클립스 스트림시트: 스트림 처리를 위한 스프레드시트 인터페이스를 제공한다.

스트림 처리 서비스
하드웨어 추상화 표준 규격하드웨어를 추상화하여 다양한 플랫폼에서 스트림 프로세싱을 가능하게 하는 표준 규격도 존재한다.

참조

[1] 웹사이트 A SHORT INTRO TO STREAM PROCESSING https://www.jonathan[...]
[2] 문서 FCUDA: Enabling Efficient Compilation of CUDA Kernels onto FPGAs http://impact.crhc.i[...]
[3] 논문 A Programmable 512 GOPS Stream Processor for Signal, Image, and Video Processing https://ieeexplore.i[...] IEEE Journal of Solid-State Circuits
[4] 논문 Exploring VLSI Scalability of Stream Processors http://cva.stanford.[...] Stanford and Rice University
[5] 논문 Stream processing in General-Purpose Processors http://www.cs.utexas[...] Stanford University
[6] 논문 Programmable Stream Processors http://cva.stanford.[...] Universities of Stanford, Rice, California (Davis) and Reservoir Labs
[7] 웹사이트 Stanford Real-Time Programmable Shading Project http://graphics.stan[...] 2017-03-09
[8] 웹사이트 The Imagine - Image and Signal Processor http://cva.stanford.[...] 2017-03-09
[9] 웹사이트 Merrimac - Stanford Streaming Supercomputer Project http://merrimac.stan[...] 2017-03-09
[10] 문서 Imagine http://cva.stanford.[...]
[11] 문서 Merrimac http://merrimac.stan[...]
[12] 간행물 2018 IEEE International Conference on Computational Science and Engineering (CSE) IEEE 2018-10
[13] 뉴스 PeakStream unveils multicore and CPU/GPU programming solution https://arstechnica.[...]
[14] 간행물 TStreams: A Model of Parallel Computation http://www.hpl.hp.co[...]
[15] 간행물 TStreams: How to Write a Parallel Program http://www.hpl.hp.co[...]
[16] 웹사이트 GitHub - walmartlabs/Mupd8: Muppet https://github.com/w[...]
[17] 웹사이트 http://arstechnica.c[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com